package bma.common.langutil.packagefw;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

import bma.common.langutil.io.IOUtil;

public abstract class PackageHandlerAbstract<ITEM_TYPE> implements
		PackageHandler {

	protected class Item {
		ClassLoader loader;
		ITEM_TYPE item;

		public Item(ClassLoader loader, ITEM_TYPE item) {
			super();
			this.loader = loader;
			this.item = item;
		}

		@Override
		public boolean equals(Object obj) {
			return loader.equals(obj);
		}

	}

	protected List<Item> loaders = new ArrayList<Item>();

	@Override
	public void openClassLoader(PackageManager pm, ClassLoader loader) {
		if (loaders.contains(loader))
			return;
		ITEM_TYPE item = null;
		try {
			item = doOpenClassLoader(pm, loader);
		} finally {
			loaders.add(new Item(loader, item));
		}
	}

	@Override
	public void closeClassLoader(PackageManager pm, ClassLoader loader) {
		int idx = loaders.indexOf(loader);
		if (idx == -1)
			return;
		Item item = loaders.get(idx);
		try {
			doCloseClassLoader(pm, item.loader, item.item);
		} finally {
			loaders.remove(loader);
		}
	}

	protected abstract ITEM_TYPE doOpenClassLoader(PackageManager pm,
			ClassLoader loader);

	protected abstract void doCloseClassLoader(PackageManager pm,
			ClassLoader loader, ITEM_TYPE item);

	// utils
	protected List<Class> findClasses(ClassLoader loader, Class cls)
			throws IOException, ClassNotFoundException {
		Enumeration<URL> list = loader.getResources("META-INF/classes/"
				+ cls.getName());
		List<Class> r = new LinkedList<Class>();
		while (list.hasMoreElements()) {
			URL url = list.nextElement();
			InputStream in = url.openStream();
			try {
				String content = new String(IOUtil.readStreamToBytes(in));
				String[] slist = content.split("\n");
				for (String str : slist) {
					str = str.trim();
					if (str.isEmpty())
						continue;
					r.add(Class.forName(str));
				}
			} finally {
				IOUtil.close(in);
			}
		}
		return r;
	}
}
